package com.ep.thirdPlatformProject.oa.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ep.thirdPlatformProject.oa.entity.OACompanyEntity;
import com.ep.thirdPlatformProject.oa.entity.OADepartmentEntity;
import com.ep.thirdPlatformProject.oa.entity.OAHrmResourceEntity;
import com.ep.thirdPlatformProject.oa.entity.vo.OAOrgChangeVO;
import com.ep.thirdPlatformProject.oa.mapper.OADepartmentMapper;
import com.ep.thirdPlatformProject.oa.service.OACompanyService;
import com.ep.thirdPlatformProject.oa.service.OADepartmentService;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@DS("oa_db")
@Slf4j
@RequiredArgsConstructor
public class OADepartmentServiceImpl extends ServiceImpl<OADepartmentMapper, OADepartmentEntity> implements OADepartmentService {

    private final OADepartmentMapper departmentMapper;

    private final OACompanyService oaCompanyService;

    private final RedisTemplate<String, OAOrgChangeVO> redisTemplate;


    private final RedisTemplate<String, OADepartmentEntity> deptTemplate;
    /**
     * OA公司名单
     */
    private final static String OA_DEPARTMENT_LIST = "OA_DEPARTMENT_LIST";

    /**
     * Oa部门路径列表
     */
    private final static String OA_DEPARTMENT_PATH_LIST = "OA_DEPARTMENT_PATH_LIST";

    /**
     * 获取变更部门列表
     *
     * @return {@link List }<{@link OAOrgChangeVO }>
     */
    @Override
    public List<OAOrgChangeVO> getDepartmentChangeList() {
        // 获取当天的开始时间
        DateTime start = DateUtil.beginOfDay(DateUtil.date());
        Boolean hasKey = redisTemplate.hasKey(OA_DEPARTMENT_LIST);
        BoundListOperations<String, OAOrgChangeVO> listOps = redisTemplate.boundListOps(OA_DEPARTMENT_LIST);
        if (Boolean.FALSE.equals(hasKey)) {
            MPJLambdaWrapper<OADepartmentEntity> queryWrapper = new MPJLambdaWrapper<OADepartmentEntity>()
                    .select(OADepartmentEntity::getId)
                    .selectAs(OADepartmentEntity::getDepartmentName, OAOrgChangeVO::getOrgName)
                    .selectAs(OADepartmentEntity::getDepartmentCode, OAOrgChangeVO::getOrgCode)
                    .selectAs(OADepartmentEntity::getTLevel, OAOrgChangeVO::getLevel)
                    .selectAs(OADepartmentEntity::getCreateTime, OAOrgChangeVO::getCreateTime)
                    .selectAs(OADepartmentEntity::getModifiedTime, OAOrgChangeVO::getModifiedTime)
                    .selectAs("c", OAHrmResourceEntity::getLastname, OAOrgChangeVO::getCreator)
                    .selectAs("b", OAHrmResourceEntity::getLastname, OAOrgChangeVO::getModifier)
                    .selectAs("b", OAHrmResourceEntity::getLastname, OAOrgChangeVO::getModifyUsername)
                    .selectAs("b", OAHrmResourceEntity::getWorkCode, OAOrgChangeVO::getModifyUserNo)
                    .leftJoin(OAHrmResourceEntity.class, "b", OAHrmResourceEntity::getId, OACompanyEntity::getModifier)
                    .leftJoin(OAHrmResourceEntity.class, "c", OAHrmResourceEntity::getId, OACompanyEntity::getCreator)
                    .ge(OADepartmentEntity::getModifiedTime, start);

            List<OAOrgChangeVO> vos = departmentMapper.selectJoinList(OAOrgChangeVO.class, queryWrapper);
            if (!vos.isEmpty()) {
                OAOrgChangeVO[] values = vos.toArray(new OAOrgChangeVO[]{});
                listOps.leftPushAll(values);
                listOps.expire(20, TimeUnit.HOURS);
            }
            return vos;
        }
        return listOps.range(0, -1);
    }

    /**
     * 填写部门实体完整STR
     *
     * @return {@link List }<{@link OADepartmentEntity }> 返回所有的部门和对应的层级
     */
    @Override
    public List<OADepartmentEntity> fillDepartmentEntityFullStr() {

        // 获取所有的公司
        List<OACompanyEntity> companyList = oaCompanyService.list();

        // 获取所有的部门
        MPJLambdaWrapper<OADepartmentEntity> queryWrapper = new MPJLambdaWrapper<OADepartmentEntity>()
                .ne(OADepartmentEntity::getCanceled, 1)
                .or()
                .isNull(OADepartmentEntity::getCanceled);
        List<OADepartmentEntity> departmentList = departmentMapper.selectJoinList(OADepartmentEntity.class, queryWrapper);


        // 组装出公司的名称
        for (OACompanyEntity company : companyList) {
            company.setFullTraceStr(company.getCompanyName());
            for (OADepartmentEntity dept : departmentList) {
                // parent为0的时候，为第一层级，组装出对应的路径
                if (dept.getCompanyId().equals(company.getId()) && 0 == dept.getParentId()) {
                    company.getChildren().add(dept);
                    // 父亲节点的值（公司层次）
                    dept.setFullPathName(company.getCompanyName() + ">" + dept.getDepartmentName());
                }
            }

        }
        // 组装出部门的全路径
        buildTree(departmentList);

        return departmentList;
    }

    /**
     * 按代码获取部门实体
     *
     * @return {@link OADepartmentEntity }
     */
    @Override
    public String getOADeptFullPathNameByCode(String deptCode) {
        if (StrUtil.isBlank(deptCode)) {
            throw new IllegalArgumentException("部门代码不能为空");
        }
        Boolean hasKey = redisTemplate.hasKey(OA_DEPARTMENT_PATH_LIST);

        if (Boolean.FALSE.equals(hasKey)) {
            // 组装对应的组织全路径
            List<OADepartmentEntity> departmentList = fillDepartmentEntityFullStr();
            BoundHashOperations<String, Object, Object> mapOps = deptTemplate.boundHashOps(OA_DEPARTMENT_PATH_LIST);
            Map<String, OADepartmentEntity> map = departmentList.stream().filter(item->StrUtil.isNotEmpty(item.getDepartmentCode()))
                    .collect(Collectors.toMap(OADepartmentEntity::getDepartmentCode, item -> item, (first, second) -> first));
            mapOps.putAll(map);
            mapOps.expire(20, TimeUnit.HOURS);

        }
        OADepartmentEntity dept = (OADepartmentEntity) deptTemplate.boundHashOps(OA_DEPARTMENT_PATH_LIST).get(deptCode);

        return Opt.ofNullable(dept).orElseThrow(() -> new RuntimeException("对应的部门编码" + deptCode + "未找到 部门全路径")).getFullPathName();

    }

    /**
     * 构建部门树结构
     *
     * @param departmentList 部门列表
     */
    public static void buildTree(List<OADepartmentEntity> departmentList) {

        // 构建部门ID与部门对象的映射关系
        Map<Integer, OADepartmentEntity> departmentMap = departmentList.stream().collect(
                Collectors.toMap(OADepartmentEntity::getId,
                        item -> item, (v1, v2) -> v1,
                        HashMap::new
                )
        );

        // 遍历部门列表，将子部门加入父部门的children列表中
        for (OADepartmentEntity department : departmentList) {
            Integer parentId = department.getParentId();
            OADepartmentEntity parent = departmentMap.get(parentId);
            if (parent != null) {
                parent.getChildren().add(department);
            }
        }

        // 填充部门的全路径
        departmentList.stream().filter(item -> 0 == item.getParentId())
                .forEach(item -> setFullPath(item, item.getFullPathName()));


    }

    /**
     * 递归 设置全路径
     *
     * @param dept     部门
     * @param basePath 基本路径
     */
    private static void setFullPath(OADepartmentEntity dept, String basePath) {
        // 如果节点为空，直接返回
        if (dept == null) {
            return;
        }
        // 递归处理子部门
        List<OADepartmentEntity> children = dept.getChildren();

        if (children != null && !children.isEmpty()) {
            for (OADepartmentEntity child : children) {
                String fullPathStr = basePath + ">" + child.getDepartmentName().trim();
                setFullPath(child, fullPathStr);
            }
        }
        // 处理非第一层级的部门 全路径
        if (0 != dept.getParentId()) {
            dept.setFullPathName(basePath);
        }

    }
}
